package cn.attaching.security;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;

/**
 * MAC 加密算法家族
 * 高杰创建于 2017/01/19.
 */
public class MacSecurity {

    public static final String HMACMD2 = "HmacMD2";
    public static final String HMACMD5 = "HmacMD5";
    public static final String HMACSHA1 = "HmacSHA1";
    public static final String HMACSHA256 = "HmacSHA256";
    public static final String HMACSHA384 = "HmacSHA384";
    public static final String HMACSHA512 = "HmacSHA512";

    /**
     * MAC算法可选以下多种算法
     * <p>
     * <pre>
     * HmacMD5
     * HmacSHA1
     * HmacSHA256
     * HmacSHA384
     * HmacSHA512
     * </pre>
     */
    public static final String KEY_MAC = "HmacMD5";

    /**
     * BASE64解码
     *
     * @param key 待解码的串
     * @return 解码结果
     * @throws Exception
     */
    public static byte[] decryptBASE64(String key) throws Exception {
        return (new BASE64Decoder()).decodeBuffer(key);
    }

    /**
     * BASE64转码
     *
     * @param key 待转码
     * @return 转码后结果
     * @throws Exception
     */
    public static String encryptBASE64(byte[] key) throws Exception {
        return (new BASE64Encoder()).encodeBuffer(key);
    }

    /**
     * 根据算法名称获取加密密钥
     *
     * @param macName MAC加密算法名称
     * @return 加密后的密钥
     * @throws Exception
     */
    public static String initMacKey(String macName) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(macName);
        SecretKey secretKey = keyGenerator.generateKey();
        return encryptBASE64(secretKey.getEncoded());
    }

    /**
     * 将字节数组进行MAC算法加密，需要提供密钥以及密钥使用的加密算法名称
     *
     * @param data    要加密的明文
     * @param key     加密的密钥
     * @param macName 加密算法名称
     * @return 加密结果
     * @throws Exception
     */
    public static byte[] encryptHMAC(byte[] data, String key, String macName) throws Exception {
        SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), macName);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        return mac.doFinal(data);
    }

    /**
     * 将明文进行MAC算法加密，需要提供密钥以及初始化密钥的加密算法名称
     *
     * @param src     要加密的明文
     * @param key     要加密的密钥
     * @param macName 加密算法名称
     * @return 加密后密文
     * @throws Exception
     */
    public static String encryptHMAC(String src, String key, String macName) throws Exception {
        SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), macName);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        mac.update(src.getBytes(Charset.forName("UTF-8")));
        byte[] after = mac.doFinal();
        return TypeConversion.bytesToHexString(after);
    }
}
